#include "FileRestore.h"
#include "input.h"
#include <unistd.h>  
#include "nfs/template/WinHexTemplate.cpp"

#define rc(c,n) for(int i;i<n;i++) printf("%c",c)

extern FileRestore *ns;

class Shell 
{
    time_t t0,t1;
    DiskInfo dinfo;
    public:
        Shell(){     }
        
        void init(string config){
            
             time(&t0);
            if(config.find("f")!=string::npos)   ns->findAll();
             time(&t1);
             
             
            if(config.find("i") !=string::npos) {
                dinfo=ns->nfs->getDiskInfo();
                this->Info();
            }
            if(config.find("r")!=string::npos)   ns->ls(-1);
           }
        
        void Info(){
            long size=dinfo.size/2/1024;
            char *dev= ds->dev;
            int      tj_giveupNum=0;
            cout << "#######################################################################\n" ;
            cout << "   搜索"<<dev<<"用时 "<<difftime(t1,t0)<<"s,一共找到文件个数： "<<ns->files.size() <<endl;
            cout << "   输入数字查看对应文件，输入 :数字 还原文件, 其他搜索文件名" <<endl;
            cout << "   磁盘信息: 共"<< dinfo.size << "簇，最小存储单位为"<< dinfo.itemSize << "簇，磁盘大小约为" << size/1024<<"G" << size%1024 << "M" <<  endl;
            cout << "   运行信息: 共放弃"<< tj_giveupNum << "个节点数据，被复写的文件目录节点"<< ns->fixfileNum << "个 " <<  endl;
            cout << "#######################################################################" << endl;
        }
        
        /**
         * 帮助信息
         */
        void help(){
            string out="\
            ^>     存储文件 \n\
            ^:     num[STGMKbBp] 跳转到位置  \n\
            ^+     方向向下,再次回车继续\n\
            ^-     方向向上\n\
            ^/     nNq,扇区搜索   \n\
            q      退出      \n\
            h      帮助     \n\
            w      w 扇区数 文件名 (扇区转存到文件) \n\
            up     上一条命令 \n\
            down  下一条命令   \n\
            pageUp   上一个扇区  \n\
            pageDown   下一个扇区  \n\
            number  查看文件 \n\
            string  搜索文件 \n\
            ctrl+t  模板选择 \n\
            ";
            cout << out ; 
            //home end left right delete tab
        }
        void dump(long index,int postion=0,int len=0){
                    char *s=ds->get(index);
                    if(postion) printf("[0x%x,%d]\n",postion,len);
                     ds->dumpPostionInfo(index);
                     ns->nfs->dump(index,len);
//                     ds->dump(s);
        }
        
        void search(const char *find,int offset=-1) {
            long p=0,postion=ds->postion;
            int direction=0;
            int i=offset;
            char *s;
            bool ok;
            
            while(true) {
                direction? postion--:postion++;
                s=ds->get(postion);
                if(offset!=-1) {
                    s+=offset;
                    string ss=ds->getHexStr(s,strlen(find)/2);
                    ok=(strcmp(ss.c_str(),find)==0);
                }else{
                    string str=ds->getHexStr(s);
                    i=str.find(find);
                    ok=(i != (int)string::npos);
                }
                
                if(!ok){
                    if(p++>10){
                        p=0;
                        cout << "\n搜索了好久["<<postion<<"]都没找到是否继续[y/n]"  ;
                        char c=getch();
                        if(c=='n') break;
                    }
                     continue;
                }else{
//                    printf("---[%ld]---\n",postion);
                    this->dump(postion,i,strlen(find));
                }
                
getnextin:                
                char c=getch();
                if(c=='q') break;
                if(c=='n'){
                    direction=0;
                }else if(c=='N') {
                    direction=1;
                }else{
                    cout << "\nq退出搜索;  n继续搜索，N反向搜索"  ;
                    goto getnextin;
                }
            }
        }
        
        void run(){
            char in[255];  
            string pwd=""; 
            string args[10];
            long index,sindex;   //当前元素index，sug猜测元素index
            char *s;
            string ss;
            input_init();
            index=ns->getRoot();
           HistoryArray<int> postionHistory;
            while(1) {
                postionHistory.push(index);
next0:   
                cout <<"\n"<< pwd<<"$ ";
next1:                
                in[0]=0;
next2:
                getInput((char *)&in);  
//                gets(in);
                if(in[1]==' '){
                    ss=in;
                    split(ss," ",args);
                    in[1]='\0';
                }
                    
                //直接回车 
                if(strlen(in)==0) {
                    //重复上一个偏移命令
                    if(strlen(in)==0 && historyCmd.size()>0){
                            cmd=historyCmd.back();
                            if(cmd.at(0)=='+' || cmd.at(0)=='-') {
                                strcpy(in,cmd.c_str());
                            }
                    }
                    if(strlen(in)==0) continue;
                }

                if(strlen(in)==1 and !atoi(in)) {
                    s=&in[2];
                    if(in[0]=='q')  break;
                    //帮助
                    if(in[0]>0)
                        switch(in[0]){
    //                        case KEY_F1+128: 
                            case 'h':           //帮助
                                help();
                                break;
                            case 'w':           //w扇区写文件
                                ds->sectorWriteto(args[1],args[2]);
                                break;
                            case '>':
                                ns->restore(index);
                                break;
                             case ':':
                                this->dump(ns->getFile(index).postion);
                                break;     
                            case 20:        //ctrl+T   模板选择 
                                WinHexTemplate_shell();
                                break;     
                          default:  
                              printf("没有找到命令:%c,%d",in[0],in[0]);
                              break;
                        }
                    else{
                        int i;
                        switch(in[0] & 0x7F){
                          case  KEY_TAB:   //tab
//                                i=strlen(s);
                                i=nShow(s);
                                sindex=ns->getSuggest(index,s,in);
                                if(i && strlen(in)>0) {
                                    if(i>0) cursorMove(-i,true); //printf("\033[%dD\033[K",i);
                                    cout << in;
                                }else{
                                    strcpy(in,s);
                                }
                                goto next2;
                                break;
                           case  KEY_PAGEUP:   //pgup
                                this->dump(ds->postion-1);
                                break;
                          case  KEY_PAGEDOWN:   //pgdown
                                ds->dump(ds->get(ds->postion+1));
                                break;           
                          case  KEY_ESC:   //esc  
                                if(s[0] ==27) {
                                    index=ns->getParent(index);
                                    pwd=ns->getPwd(index);
                                    break;
                                }
                                cursorMove(-nShow(s),true);
//                                printf("\033[%ldD\033[K",strlen(s));
                                i=(strrchr(s,'/') !=NULL) ? strrchr(s,'/')-s :0;
                                s[i]=0;
                                if(i) printf("%s",s);
                                strcpy(in,s);
                                goto next2;
                                break;
                            default:
                                //历史记录实现  
                                if(strncmp(s,"\x1b\x5b\x31\x3b\x33",5)==0) {
                                    switch(s[5]) {
                                        case 68:  //alt+<
                                            index=postionHistory.get(-1);
                                            break;
                                        case 67:  //alt+>
                                            index=postionHistory.get(1);
                                            break;
                                    }
                                    this->dump(index);
                                    goto next0;
                                }
                                printf("未处理的按键:%d",in[0] & 0x7F);
                                break;
                        }
                  }
                  continue;
              }
                //特殊字符 
                else if(!(in[0]>=48 && in[0]<58) && in[0]<64){
                    s=substr(in,1,-1);
                    switch(in[0]){
                        //另存
                        case '>':
                            index=strlen(s)>0 ? atoi(s) : index;
                            ns->restore(index);
                            break;
                          //搜索扇区
                        case '/':
                            if(strstr(s,"/")!=NULL || sindex!=0 ) goto outnode;
                             ss=s;
                             split(ss," ",args);
                             index=atoi(args[1].c_str());
                            this->search(args[0].c_str(),index?index:-1);
                            break;
                            //先前走多少
                        case '+':
                            index=ds->postion + ds->getCount(s);
                            this->dump(index);
                            break;
                            //向后走多少
                        case '-':  
                            index=ds->postion - ds->getCount(s);
                            this->dump(index);
                            break;
                       //查看扇区信息
                        case ':':
                          index= ds->getCount(s);
                          this->dump(index);
                          break;     
                        default:
                            break;
                    }
                    continue;
                }
                else {
outnode: 
                    //搜索
                     if(!isNumber(in)){
                             //最后一个字符不是数字  
                                if(isNumber(in,strlen(in)-1)) {
                                      index= ds->getCount(in);
                                      this->dump(index);
                                      continue;
                                }
                                sindex=ns->findByName(in,index);
                                if(sindex!=0) {
                                    index=sindex;
                                }else{
                                     continue;
                                }
                    }else{
                         index=atoi(in);
                    }
                    
                    //查看inode
                    if(ns->ls(index))
                        pwd=ns->getPwd(index);
                    sindex=0;
                }
            }

            printf("good-bye!\n");
        }
    private:
};
